工具类采用:Hutool依赖

// 微信V3支付
public JSONObject wechatPayJsApi() throws Exception {
String url = StrUtil.format("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
String appid = "微信公众号appid";
String mchId = "微信商户mchid";
String notifyUrl = "支付成功回调地址";
String nonceStr = IdUtil.simpleUUID();
String timestamp = System.currentTimeMillis() / 1000;
JSONObject jsonObject = new JSONObject();
jsonObject.set("appid", appid);
jsonObject.set("mchid", mchId);
jsonObject.set("description", "商品的名称");
jsonObject.set("out_trade_no", DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmssSSS"));
jsonObject.set("notify_url", notifyUrl);

jsonObject.set("amount",
new JSONObject()
.set("total", 金额(分))
);
jsonObject.set("scene_info",
new JSONObject()
.set("payer_client_ip", "支付的ip")
);
jsonObject.set("payer",
new JSONObject()
.set("openid", "微信用户openId")
);

HttpResponse execute = HttpUtil.createPost(url)
.header("Content-Type", "application/json;chartset=utf-8")
.header("Accept", "application/json")
.header("Authorization", getToken("POST", new URL(url), jsonObject.toString()))
.body(jsonObject.toString())
.execute();
if(execute.getStatus() != 200) {
log.info("微信支付错误信息:" + execute.body());
return execute.body();
} else {
String jsonResult = execute.body();
boolean isJson = JSONUtil.isJson(jsonResult);
if (!isJson) {
log.info("payJSAPI 错误的返回值:" + jsonResult);
return jsonResult;
}
JSONObject json = JSONUtil.parseObj(jsonResult);
if (null == json.getStr("prepay_id")) {
log.info("payJSAPI 错误的返回值:" + jsonResult);
return jsonResult;
}

String packageStr = "prepay_id=" + json.getStr("prepay_id");
String message = StrUtil.format("{}\n{}\n{}\n{}\n",
APP_ID, timestamp, nonceStr, packageStr);
String signature = sign(message.getBytes(StandardCharsets.UTF_8));
// 组装返回
JSONObject result = new JSONObject();
result.set("appId", APP_ID);
result.set("timeStamp", String.valueOf(timestamp));
result.set("nonceStr", nonceStr);
result.set("package", packageStr);
result.set("signType", "RSA");
result.set("paySign", signature);
return result.toString();
}
}

// 生成签名
public static String getToken(String method, URL url, String body) throws Exception {
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes(StandardCharsets.UTF_8));

return StrUtil.format("WECHATPAY2-SHA256-RSA2048 mchid=\"{}\",nonce_str=\"{}\",timestamp=\"{}\",serial_no=\"{}\",signature=\"{}\"",
MCH_ID, nonceStr, timestamp, MERCHANT_SERIAL_NUMBER, signature);
}
// 组合签名
public static String buildMessage(String method, URL url, long timestamp, String nonceStr, String body) {
String canonicalUrl = url.getPath();
if (url.getQuery() != null) { canonicalUrl += "?" + url.getQuery(); }
return StrUtil.format("{}\n{}\n{}\n{}\n{}\n",
method, canonicalUrl, timestamp, nonceStr, body);
}
// 获取证书
private static String sign(byte[] message) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
Signature sign = Signature.getInstance("SHA256withRSA"); //SHA256withRSA
sign.initSign(getPrivateKey("你的商务支付证书目录/apiclient_key.pem"));
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
// 获取私钥
public static PrivateKey getPrivateKey(String filename) throws IOException {
String content = new String(Files.readAllBytes(Paths.get(filename)), StandardCharsets.UTF_8);

try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");

KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}